/* global define */

/**
 * 地区选择插件
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
;
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as anonymous module.
        define(['jquery', 'ChineseDistricts'], factory);
    } else if (typeof exports === 'object') {
        // Node / CommonJS
        factory(require('jquery'), require('ChineseDistricts'));
    } else {
        // Browser globals.
        factory(jQuery, ChineseDistricts);
    }
})(function ($, ChineseDistricts) {

    'use strict';

    if (typeof ChineseDistricts === 'undefined') {
        throw new Error('The file "city-picker.data.js" must be included first!');
    }

    var NAMESPACE = 'distPicker';
    var EVENT_CHANGE = 'change.' + NAMESPACE;
    var PROVINCE = 'province';
    var CITY = 'city';
    var DISTRICT = 'district';
    var DISTRICT_LEVEL = 3;

    var DistPicker = function (element, options) {
        this.$element = $(element);
        this.$dropdown = null;
        this.$pickerbox = null;
        this.$modal = null;
        this.$result = {};
        this.options = $.extend({}, DistPicker.DEFAULTS, $.isPlainObject(options) && options);
        this.active = false;
        this.dems = [];
        this.keywords = [];
        this.needBlur = false;
        this.init();
    };

    var arrayObject = function (key, value) {
        if (key.length !== value.length) {
            return;
        }
        var info = {};
        for (var i = 0; i < key.length; i++) {
            info[key[i]] = value[i];
        }
        return info;
    };

    DistPicker.prototype = {
        constructor: DistPicker,

        init: function () {

            this.defineDems();

            this.render();

            this.bind();

            this.active = true;
        },

        render: function () {

            this.$element.attr('data-toggle', 'modal');
            this.$element.attr('data-target', '#' + this.options.modal);
            this.$element.attr('data-backdrop', 'static');
            this.$element.attr('data-keyboard', false);

            var modal = [
                // tabindex is required for focus
                '<div class="modal fade" tabindex="-1" id="' + this.options.modal + '">',
                '<div class="modal-dialog">',
                '<div class="modal-content">',
                '<div class="modal-header">',
                '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                '<h4 class="modal-title">' + this.$element.attr('title') + '</h4>',
                '</div>',
                '<div class="modal-body">',
                '<div class="dist-picker-container"></div>',
                '</div>',
                '<div class="modal-footer">',
                '<a href="#" data-dismiss="modal" class="btn btn-default">Close</a>',
                '<a href="javascript:;" class="btn btn-primary distpicker-confirm">确定</a>',
                '</div>',
                '</div>',
                '</div>',
                '</div>'
            ].join('');

            this.$modal = $(modal).appendTo($(document.body));

            var $container = $('<div class="distpicker-container">').insertAfter(this.$modal.find('.dist-picker-container'));

            var pickerResult = '<div class="distpicker-result"><em>' + (this.options.multi ? '可选择多项' : '最多选择1项') + '</em></div>';
            var pickerSearch = '<div class="distpicker-search" id="searchRun"><input class="run" name="searcharea"><div class="searchList run"></div></div>';
            var pickerBox = '<div class="distpicker-box">' +
                    '<div class="distpicker-tabs">' +
                    '<ul>' +
                    '<li class="active" data-selector="province">' +
                    '<span>全部</span><em></em>' +
                    '</li>' +
                    '</ul>' +
                    '</div>' +
                    '<div class="distpicker-content"></div>' +
                    '</div>';

            this.$pickerresult = $(pickerResult).appendTo($container);
            this.$pickersearch = $(pickerSearch).appendTo($container);
            this.$pickerbox = $(pickerBox).appendTo($container);

            var distpickertext = '<span class="dispicker-text"></span>';
            this.$distpickerinput = this.$element.find('input');
            this.$distpickertext = $(distpickertext).appendTo(this.$element);

            this.refresh();
        },

        refresh: function () {
            var $result = [];
            if (this.$element.data("code")) {
                var code = this.$element.data("code").toString();
                var codes = this.getText(code.split(','));
                var names = [];
                if (codes.length > 0) {
                    this.$distpickerinput.val(code);
                    for (var i in codes) {
                        $result.push({
                            code: codes[i].code,
                            address: codes[i].name
                        });
                        this.$pickerresult.append('<span data-code="' + codes[i].code + '" data-name="' + codes[i].name + '">' + codes[i].name + '<i>×</i></span>');
                        names.push(codes[i].name);
                    }
                }
                this.$distpickertext.text(names.join('-'));
            }
            this.$pickerresult.data('item', $result);
            var $select = this.$pickerbox.find('.distpicker-content');
            $select.data('item', null);
            var $tab = this.$pickerbox.find('.distpicker-tabs li.active');
            $tab.siblings().removeClass('active');
            $tab.nextAll('li').remove();
            this.renderArea($tab.data("selector"));

        },

        bind: function () {
            var $this = this;

            $(document).on('click', (this._mouteclick = function (e) {
                var $target = $(e.target);
                var $item;
                if ($target.is('.distpicker-result span')) {
                    $item = $target;
                } else if ($target.is('.distpicker-result span *')) {
                    $item = $target.parents('.distpicker-result span');
                }
                if ($item) {
                    $this.removeItem($item);
                }
            }));


            this.$pickerbox.on('click', '.distpicker-content a[data-leaf]:not(.disabled)', function () {
                var $result = $this.$pickerresult.data('item');
                var code = $(this).data('code').toString();
                var type = $(this).data('type');
                var address = $(this).attr('title');

                //切换选中状态 && 设置选中结果
                if ($(this).hasClass('active')) {
                    $(this).removeClass('active');
                    //设置选中结果
                    $result = $.grep($result, function (n, i) {
                        return n.code !== code;
                    });
                } else {
                    $(this).addClass('active');
                    $result.push({
                        code: code,
                        address: address
                    });
                }
                if (!$this.options.multi) {
                    $(this).siblings().removeClass('active');
                }
                if (type === 'all') {
                    var $items = $(this).parents('dl').find('dd a');
                    //移除子项结果
                    $.each($items, function () {
                        var activecode = $(this).data('code').toString();
                        if ($(this).hasClass('active')) {
                            $(this).find('span').text('0').hide();
                            $result = $.grep($result, function (n, i) {
                                return n.code !== activecode;
                            });
                        } else if (Number($(this).find('span').text()) > 0) {
                            $(this).find('span').text('0').hide();
                            $result = $.grep($result, function (n, i) {
                                var dd = $this.getParentText(n.code);
                                return dd.parent !== activecode;
                            });
                        }
                    });
                    if ($(this).hasClass('active')) {
                        $items.removeClass('active').addClass('disabled');
                    } else {
                        $items.removeClass('disabled');
                    }
                }
                $this.$pickerresult.data('item', $result);
                $this.$pickerresult.trigger(EVENT_CHANGE);
            }).on('click', '.distpicker-content a:not([data-leaf]):not(.disabled)', function () {
                var type = $(this).parent().data('type');
                var $select = $(this).parents('.distpicker-content');
                var code = $(this).data('code').toString();
                var address = $(this).attr('title');
                var level = false;
                if (type === PROVINCE) {
                    level = CITY;
                } else if (type === CITY) {
                    level = DISTRICT;
                }
                $select.data('item', {
                    code: code,
                    address: address
                });
                var newtab = '<li class="active" data-selector="' + level + '">' +
                        '<span>' + $(this).attr('title') + '</span>' +
                        '</li>';
                var $newtab = $(newtab).appendTo($this.$pickerbox.find('.distpicker-tabs ul'));
                $newtab.siblings().removeClass('active');
                $newtab.data('item', {
                    address: $(this).attr('title'),
                    code: $(this).data('code').toString()
                });
                $this.renderArea(level);
            }).on('click', '.distpicker-tabs li', function () {
                var $select = $this.$pickerbox.find('.distpicker-content');
                $select.data('item', $(this).data('item'));
                $(this).siblings().removeClass('active');
                $(this).addClass('active');
                if (!$(this).nextAll('li').length) {
                    return false;
                }
                $(this).nextAll('li').remove();
                $this.renderArea($(this).data("selector"));
            }).on('mousedown', function () {
                $this.needBlur = false;
            });
            this.$modal.on('click', '.distpicker-confirm', function () {
                var $result = $this.$pickerresult.data('item');
                var codes = [], values = [];
                for (var i in $result) {
                    codes.push($result[i].code.toString());
                    values.push($result[i].address);
                }
                if ($this.$distpickerinput) {
                    $this.$distpickerinput.val(codes.join(','));
                }
                $this.$element.data('code', codes.join(','));
                $this.$distpickertext.text(values.join('-'));
                $('#' + $this.options.modal).modal('hide');
            });
            if (this.$pickerresult) {
                this.$pickerresult.on(EVENT_CHANGE, (this._changeResult = $.proxy(function () {
                    $this.renderResult();
                }, this)));
            }
        },

        renderResult: function () {
            var $result = this.$pickerresult.data('item');
            this.$pickerresult.find('span').remove();
            for (var i in $result) {
                this.$pickerresult.append('<span data-code="' + $result[i].code + '" data-name="' + $result[i].address + '">' + $result[i].address + '<i>×</i></span>');
            }
        },

        renderArea: function (type) {
            var options = this.options;
            var $select = this.$pickerbox.find('.distpicker-content');
            var $result = this.$pickerresult.data('item');
            var $codes = [];
            var data = type === PROVINCE ? {} : [];
            var item;
            var districts;
            var itemcode;
            var matched = [];
            var value;
            if (!$select || !$select.length) {
                return;
            }
            for (var i = 0, len = $result.length; i < len; i++) {
                $codes.push($result[i].code);
            }
            var level = this.getCodeNumber($result);

            item = $select.data('item');
            if (item) {
                item['count'] = (level && level[item.code]) ? level[item.code] : 0;
                item['selected'] = $.inArray(item.code, $codes) >= 0 ? true : false;
            }
            value = (item ? item.address : '') || options[type];
            itemcode = type === PROVINCE ? 86 : (item ? item.code : itemcode);
            districts = $.isNumeric(itemcode) ? ChineseDistricts[itemcode] : null;
            if (type === PROVINCE) {
//                districts = $.extend({
//                    'hot': [
//                        {code: '340000', name: '安徽省'},
//                    ]
//                }, districts);
            }
            if ($.isPlainObject(districts)) {
                $.each(districts, function (code, address) {
                    var provs;
                    var actived = false;
                    if (type === PROVINCE) {
                        provs = [];
                        for (var i = 0; i < address.length; i++) {
                            actived = $.inArray(address[i].code, $codes) >= 0 ? true : false;
                            if (actived) {
                                matched.push({
                                    code: address[i].code,
                                    address: address[i].name
                                });
                            }
                            var count = (level && level[address[i].code]) ? level[address[i].code] : 0;
                            provs.push({
                                code: address[i].code,
                                address: address[i].name,
                                count: count,
                                selected: actived
                            });
                        }
                        data[code] = provs;
                    } else {
                        actived = $.inArray(code, $codes) >= 0 ? true : false;
                        if (actived) {
                            matched.push({
                                code: code,
                                address: address.name
                            });
                        }
                        var count = (level && level[code]) ? level[code] : 0;
                        data.push({
                            code: code,
                            address: address.name,
                            count: count,
                            selected: actived
                        });
                    }
                });
                if (type !== PROVINCE) {
                    data['all'] = {
                        code: itemcode,
                        address: value
                    };
                }
            }
            $select.html(type === PROVINCE ? this.getHomeList(data) : this.getSideList(data, type, item));
            $select.data('item', matched);
        },

        getHomeList: function (data) {
            var list = [],
                    $this = this,
                    simple = this.options.simple;
            $.each(data, function (i, n) {
                list.push('<dl class="clearfix">');
                list.push('<dt>' + i + '</dt>');
                list.push('<dd>');
                $.each(n, function (j, m) {
                    var leaf = ChineseDistricts && ChineseDistricts[m.code];
                    var count = m.count ? '<span style="display: inline-block;">' + m.count + '</span>' : '<span>0</span>';
                    list.push(
                            '<a' +
                            ' title="' + (m.address || '') + '"' +
                            ' data-code="' + (m.code || '') + '"' +
                            (!leaf ? ' data-leaf="true"' : '') +
                            ' class="' +
                            (m.selected ? ' active' : '') +
                            '">' +
                            (simple ? $this.simplize(m.address, PROVINCE) : m.address) +
                            (leaf ? count : '') +
                            '</a>');
                });
                list.push('</dd></dl>');
            });
            return list.join('');
        },

        getSideList: function (data, type, parent) {
            var list = [],
                    $this = this,
                    simple = this.options.simple;
            list.push('<dl class="clearfix">');
            if (parent) {
                list.push('<dt>' +
                        '<a' +
                        ' title="' + (parent.address || '') + '"' +
                        ' data-code="' + (parent.code || '') + '"' +
                        ' data-leaf="true"' +
                        ' data-type="all"' +
                        ' class="' +
                        (parent.selected ? ' active' : '') +
                        '">' +
                        (simple ? $this.simplize(parent.address, type) : parent.address) +
                        '</a>' +
                        '</dt>');
            }
            list.push('<dd>');
            $.each(data, function (i, n) {
                var leaf = ChineseDistricts && ChineseDistricts[n.code];
                var count = n.count ? '<span style="display: inline-block;">' + n.count + '</span>' : '<span>0</span>';
                list.push(
                        '<a' +
                        ' title="' + (n.address || '') + '"' +
                        ' data-code="' + (n.code || '') + '"' +
                        (!leaf ? ' data-leaf="true"' : '') +
                        ' class="' +
                        (n.selected ? ' active' : '') +
                        (parent && parent.selected ? ' disabled' : '') +
                        '">' +
                        (simple ? $this.simplize(n.address, type) : n.address) +
                        (leaf ? count : '') +
                        '</a>');
            });
            list.push('</dd></dl>');
            return list.join('');
        },

        getCodeNumber: function ($result) {
            if (!$result || !$result.length) {
                return;
            }
            var level = {};
            for (var i = 0, len = $result.length; i < len; i++) {
                this.recursion($result[i].code, level);
            }
            return level;
        },

        removeItem: function ($dom) {
            var code = $dom.data("code").toString();
            this.$pickerbox.find('a[data-code=' + code + ']').removeClass('active');
            var $result = this.$pickerresult.data('item');
            $result = $.grep($result, function (n, i) {
                return n.code !== code;
            });
            this.$pickerresult.data('item', $result);
            this.$pickerresult.trigger(EVENT_CHANGE);
        },

        unbind: function () {
            $(document).off('click', this._mouteclick);
            this.$element.off('change', this._changeElement);
            this.$element.off('focus', this._focusElement);
            this.$element.off('blur', this._blurElement);
        },

        defineDems: function () {
            var stop = false;
            $.each([PROVINCE, CITY, DISTRICT], $.proxy(function (i, type) {
                if (!stop) {
                    this.dems.push(type);
                }
                if (type === this.options.level) {
                    stop = true;
                }
            }, this));
            this.dems.push('hot');
            this.setDistricts();
            this.setKeywords();
        },

        setKeywords: function () {
            var data = ChineseDistricts;
            var root = this.options.root;
            var temp = [];
            var str = '';
            $.each(data, function (code, address) {
                if (code === root) {
                    $.each(address, function (c, node) {
                        if ($.isPlainObject(node)) {
                            str = c + '|' + node.name + '|' + node.en + '|' + node.abbr + '|' + root;
                            temp.push(str);
                        } else {
                            for (var i in node) {
                                str = node[i].code + '|' + node[i].name + '|' + node[i].en + '|' + node[i].abbr + '|' + root;
                                temp.push(str);
                            }
                        }
                    });
                } else {
                    for (var i in address) {
                        str = i + '|' + address[i].name + '|' + address[i].en + '|' + address[i].abbr + '|' + code;
                        temp.push(str);
                    }
                }
            });
            this.keywords = temp;
        },

        setDistricts: function () {
            var end = this.options.end;
            if (end === DISTRICT_LEVEL) {
                return;
            }
            var root = this.options.root;
            var data = ChineseDistricts;
            var parent = data[root];
            var temp = [root];
            $.each(parent, function (code, address) {
                if ($.isPlainObject(address)) {
                    temp.push(code);
                } else {
                    for (var i in address) {
                        temp.push(address[i].code);
                    }
                }
            });
            if (temp.length > 0) {
                end -= 2;
            }
            for (var i = 0; i < end; i++) {
                for (var j in temp) {
                    var key = temp[j];
                    if (!data[key]) {
                        continue;
                    }
                    $.each(data[key], function (code, address) {
                        temp.push(code);
                    });
                }
            }
            $.each(data, function (code, address) {
                if ($.inArray(code, temp) < 0) {
                    delete data[code];
                }
            });
            ChineseDistricts = data;
        },

        includeDem: function (type) {
            return $.inArray(type, this.dems) !== -1;
        },

        recursion: function (code, $return) {
            var $node = this.getParentText(code);
            if (!$node) {
                return;
            }
            var $parent = $node.parent;
            if ($parent !== this.options.root) {
                if (typeof $return[$parent] === 'undefined') {
                    $return[$parent] = 1;
                    this.recursion($parent, $return);
                } else {
                    $return[$parent] += 1;
                }
            }
            $return[code] = 1;
            return $return;
        },

        getParentText: function (code) {
            var keywords = this.keywords;
            var node = [];
            for (var i = 0, len = keywords.length; i < len; i++) {
                if (keywords[i].indexOf(code) >= 0) {
                    node = keywords[i].split('|');
                    break;
                }
            }
            return arrayObject(['code', 'name', 'en', 'abbr', 'parent'], node);
        },

        getText: function (codes) {
            if (!codes.length) {
                return [];
            }
            var string = codes.pop();
            var data = [];
            var keywords = this.keywords;
            for (var i = 0, len = keywords.length; i < len; i++) {
                if (keywords[i].indexOf(string) >= 0) {
                    var obj = arrayObject(['code', 'name', 'en', 'abbr', 'parent'], keywords[i].split('|'));
                    data.push(obj);
                    string = codes.pop();
                    i = 0;
                }
            }
            return data;
        },

        simplize: function (address, type) {
            address = address || '';
            if (type === PROVINCE) {
                return address.replace(/[省,市,自治区,壮族,回族,维吾尔]/g, '');
            } else if (type === CITY) {
                return address.replace(/[市,地区,回族,蒙古,苗族,白族,傣族,景颇族,藏族,彝族,壮族,傈僳族,布依族,侗族]/g, '').replace('哈萨克', '').replace('自治州', '').replace(/自治县/, '');
            } else if (type === DISTRICT) {
                return address.length > 2 ? address.replace(/[市,区,县,旗]/g, '') : address;
            }
        },

        destroy: function () {
            this.unbind();
            this.$element.removeData(NAMESPACE).removeClass('distpicker-input');
        }
    };

    DistPicker.DEFAULTS = {
        simple: false,
        responsive: false,
        multi: true,
        placeholder: '请选择省/市/区',
        level: 'district',
        end: 3,
        root: '86',
        province: '',
        city: '',
        district: '',
        modal: 'dist-picker-modal'
    };

    DistPicker.setDefaults = function (options) {
        $.extend(DistPicker.DEFAULTS, options);
    };

    // Save the other distPicker
    DistPicker.other = $.fn.distPicker;

    // Register as jQuery plugin
    $.fn.distPicker = function (method) {
        var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function () {
            var $this = $(this);
            var data = $this.data(NAMESPACE);

            var options;
            var fn;
            if (typeof data === 'undefined') {
                if (/destroy/.test(method)) {
                    return;
                }
                options = $.extend({}, $this.data(), $.isPlainObject(method) && method);
                $this.data(NAMESPACE, (data = new DistPicker(this, options)));

            }
            if (typeof method === 'string' && $.isFunction(fn = data[method])) {
                fn.apply(data, args);
            }
        });
    };

    $.fn.distPicker.Constructor = DistPicker;
    $.fn.distPicker.setDefaults = DistPicker.setDefaults;

    // No conflict
    $.fn.distPicker.noConflict = function () {
        $.fn.distPicker = DistPicker.other;
        return this;
    };

    $(function () {
        $('[data-toggle="dist-picker"]').distPicker();
    });
});